import java.util.ArrayList;
import java.util.HashMap;


public class Pinger implements Runnable{
	private Thread thread;
	private boolean isRunning;
	
	@Override
	public void run()
	{
		this.isRunning = true;
		while (this.isRunning)
		{
			try
			{
				// Send a ping request to every active client
				ArrayList<Client> activeClients = ConnectionHandler.getInstance().getActiveClients();
				int activeClientCount = activeClients.size();
				String allPings = "8_"; // used for sending the current pings of all clients to all clients
				for (int i = 0; i < activeClientCount; i++)
				{
					Client client = activeClients.get(i);
					int pingId = client.getPingCounter();
					String tcpdata = "1_" + pingId;
					ConnectionHandler.getInstance().sendToSingleClient(tcpdata, client);
					
					// Store the id and timestamp of this ping request for ping calculation
					HashMap<Integer, Long> pingStartTimes = client.getPingStartTimes();
					synchronized (pingStartTimes){
						
						long currentTime = System.nanoTime();
						pingStartTimes.put(pingId, currentTime);
					}
					client.setPingCounter(pingId + 1);
					
					// Add this client's ping to the 'allPings' string
					if (i > 0)
						allPings += "#";
					allPings += client.getClientId() + ":" + client.getPing();
				}
				
				// Send the current ping to all clients (used for displaying in the game client's score board)
				ConnectionHandler.getInstance().sendToAllClients(allPings);
				
				Thread.sleep(Settings.pingDelay);
			}
			catch (Exception e) {}
		}
	}
	
	/**
	 * Start pinging all clients.
	 */
	public void start() // started in BufferedTcpSender
	{
		thread = new Thread(this);
		thread.start();
	}
	
	/**
	 * Stop pinging all clients.
	 */
	public void stop() // stopped in BufferedTcpSender
	{
		this.isRunning = false;
		thread = null;
	}
	
	/**
	 * Receives the latest ping for a client, adding the ping of the specified client to its pingbuffer.
	 * @param client The client of which a new ping value is received.
	 * @param pingId The id of the ping request that is responded to by the client.
	 */
	public void receivePing(Client client, int pingId)
	{
		HashMap<Integer, Long> pingStartTimes = client.getPingStartTimes();
		if (pingStartTimes.get(pingId) != null)
		{
			long startTime = pingStartTimes.get(pingId);
			long endTime = System.nanoTime();
			long timeDifference = endTime - startTime;
			int pingInMs = (int)(timeDifference / 1000000);
			client.addToPingBuffer(pingInMs);
			pingStartTimes.remove(pingId);
		}
	}
}
